(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.qwest = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
// shim for using process in browser

var process = module.exports = {};
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;

function cleanUpNextTick() {
    draining = false;
    if (currentQueue.length) {
        queue = currentQueue.concat(queue);
    } else {
        queueIndex = -1;
    }
    if (queue.length) {
        drainQueue();
    }
}

function drainQueue() {
    if (draining) {
        return;
    }
    var timeout = setTimeout(cleanUpNextTick);
    draining = true;

    var len = queue.length;
    while(len) {
        currentQueue = queue;
        queue = [];
        while (++queueIndex < len) {
            if (currentQueue) {
                currentQueue[queueIndex].run();
            }
        }
        queueIndex = -1;
        len = queue.length;
    }
    currentQueue = null;
    draining = false;
    clearTimeout(timeout);
}

process.nextTick = function (fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
        setTimeout(drainQueue, 0);
    }
};

// v8 likes predictible objects
function Item(fun, array) {
    this.fun = fun;
    this.array = array;
}
Item.prototype.run = function () {
    this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};

function noop() {}

process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;

process.binding = function (name) {
    throw new Error('process.binding is not supported');
};

process.cwd = function () { return '/' };
process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };

},{}],2:[function(_dereq_,module,exports){
/**
 * @preserve jquery-param (c) 2015 KNOWLEDGECODE | MIT
 */
/*global define */
(function (global) {
    'use strict';

    var param = function (a) {
        var add = function (s, k, v) {
            v = typeof v === 'function' ? v() : v === null ? '' : v === undefined ? '' : v;
            s[s.length] = encodeURIComponent(k) + '=' + encodeURIComponent(v);
        }, buildParams = function (prefix, obj, s) {
            var i, len, key;

            if (Object.prototype.toString.call(obj) === '[object Array]') {
                for (i = 0, len = obj.length; i < len; i++) {
                    buildParams(prefix + '[' + (typeof obj[i] === 'object' ? i : '') + ']', obj[i], s);
                }
            } else if (obj && obj.toString() === '[object Object]') {
                for (key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        if (prefix) {
                            buildParams(prefix + '[' + key + ']', obj[key], s, add);
                        } else {
                            buildParams(key, obj[key], s, add);
                        }
                    }
                }
            } else if (prefix) {
                add(s, prefix, obj);
            } else {
                for (key in obj) {
                    add(s, key, obj[key]);
                }
            }
            return s;
        };
        return buildParams('', a, []).join('&').replace(/%20/g, '+');
    };

    if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = param;
    } else if (typeof define === 'function' && define.amd) {
        define([], function () {
            return param;
        });
    } else {
        global.param = param;
    }

}(this));

},{}],3:[function(_dereq_,module,exports){
(function (process){
/*
 * PinkySwear.js 2.2.2 - Minimalistic implementation of the Promises/A+ spec
 * 
 * Public Domain. Use, modify and distribute it any way you like. No attribution required.
 *
 * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 *
 * PinkySwear is a very small implementation of the Promises/A+ specification. After compilation with the
 * Google Closure Compiler and gzipping it weighs less than 500 bytes. It is based on the implementation for 
 * Minified.js and should be perfect for embedding. 
 *
 *
 * PinkySwear has just three functions.
 *
 * To create a new promise in pending state, call pinkySwear():
 *         var promise = pinkySwear();
 *
 * The returned object has a Promises/A+ compatible then() implementation:
 *          promise.then(function(value) { alert("Success!"); }, function(value) { alert("Failure!"); });
 *
 *
 * The promise returned by pinkySwear() is a function. To fulfill the promise, call the function with true as first argument and
 * an optional array of values to pass to the then() handler. By putting more than one value in the array, you can pass more than one
 * value to the then() handlers. Here an example to fulfill a promsise, this time with only one argument: 
 *         promise(true, [42]);
 *
 * When the promise has been rejected, call it with false. Again, there may be more than one argument for the then() handler:
 *         promise(true, [6, 6, 6]);
 *         
 * You can obtain the promise's current state by calling the function without arguments. It will be true if fulfilled,
 * false if rejected, and otherwise undefined.
 * 		   var state = promise(); 
 * 
 * https://github.com/timjansen/PinkySwear.js
 */
(function(target) {
	var undef;

	function isFunction(f) {
		return typeof f == 'function';
	}
	function isObject(f) {
		return typeof f == 'object';
	}
	function defer(callback) {
		if (typeof setImmediate != 'undefined')
			setImmediate(callback);
		else if (typeof process != 'undefined' && process['nextTick'])
			process['nextTick'](callback);
		else
			setTimeout(callback, 0);
	}

	target[0][target[1]] = function pinkySwear(extend) {
		var state;           // undefined/null = pending, true = fulfilled, false = rejected
		var values = [];     // an array of values as arguments for the then() handlers
		var deferred = [];   // functions to call when set() is invoked

		var set = function(newState, newValues) {
			if (state == null && newState != null) {
				state = newState;
				values = newValues;
				if (deferred.length)
					defer(function() {
						for (var i = 0; i < deferred.length; i++)
							deferred[i]();
					});
			}
			return state;
		};

		set['then'] = function (onFulfilled, onRejected) {
			var promise2 = pinkySwear(extend);
			var callCallbacks = function() {
	    		try {
	    			var f = (state ? onFulfilled : onRejected);
	    			if (isFunction(f)) {
		   				function resolve(x) {
						    var then, cbCalled = 0;
		   					try {
				   				if (x && (isObject(x) || isFunction(x)) && isFunction(then = x['then'])) {
										if (x === promise2)
											throw new TypeError();
										then['call'](x,
											function() { if (!cbCalled++) resolve.apply(undef,arguments); } ,
											function(value){ if (!cbCalled++) promise2(false,[value]);});
				   				}
				   				else
				   					promise2(true, arguments);
		   					}
		   					catch(e) {
		   						if (!cbCalled++)
		   							promise2(false, [e]);
		   					}
		   				}
		   				resolve(f.apply(undef, values || []));
		   			}
		   			else
		   				promise2(state, values);
				}
				catch (e) {
					promise2(false, [e]);
				}
			};
			if (state != null)
				defer(callCallbacks);
			else
				deferred.push(callCallbacks);
			return promise2;
		};
        if(extend){
            set = extend(set);
        }
		return set;
	};
})(typeof module == 'undefined' ? [window, 'pinkySwear'] : [module, 'exports']);


}).call(this,_dereq_('_process'))
},{"_process":1}],"qwest":[function(_dereq_,module,exports){
/*! qwest 2.2.2 (https://github.com/pyrsmk/qwest) */

module.exports = function() {

	var global = window || this,
		pinkyswear = _dereq_('pinkyswear'),
		jparam = _dereq_('jquery-param'),
		// Default response type for XDR in auto mode
		defaultXdrResponseType = 'json',
		// Variables for limit mechanism
		limit = null,
		requests = 0,
		request_stack = [],
		// Get XMLHttpRequest object
		getXHR = function(){
			return global.XMLHttpRequest?
					new global.XMLHttpRequest():
					new ActiveXObject('Microsoft.XMLHTTP');
		},
		// Guess XHR version
		xhr2 = (getXHR().responseType===''),

	// Core function
	qwest = function(method, url, data, options, before) {

		// Format
		method = method.toUpperCase();
		data = data || null;
		options = options || {};

		// Define variables
		var nativeResponseParsing = false,
			crossOrigin,
			xhr,
			xdr = false,
			timeoutInterval,
			aborted = false,
			attempts = 0,
			headers = {},
			mimeTypes = {
				text: '*/*',
				xml: 'text/xml',
				json: 'application/json',
				post: 'application/x-www-form-urlencoded'
			},
			accept = {
				text: '*/*',
				xml: 'application/xml; q=1.0, text/xml; q=0.8, */*; q=0.1',
				json: 'application/json; q=1.0, text/*; q=0.8, */*; q=0.1'
			},
			vars = '',
			i, j,
			serialized,
			response,
			sending = false,
			delayed = false,
			timeout_start,

		// Create the promise
		promise = pinkyswear(function(pinky) {
			pinky['catch'] = function(f) {
				return pinky.then(null, f);
			};
			pinky.complete = function(f) {
				return pinky.then(f, f);
			};
			// Override
			if('pinkyswear' in options) {
				for(i in options.pinkyswear) {
					pinky[i] = options.pinkyswear[i];
				}
			}
			pinky.send = function() {
				// Prevent further send() calls
				if(sending) {
					return;
				}
				// Reached request limit, get out!
				if(requests == limit) {
					request_stack.push(pinky);
					return;
				}
				++requests;
				sending = true;
				// Start the chrono
				timeout_start = new Date().getTime();
				// Get XHR object
				xhr = getXHR();
				if(crossOrigin) {
					if(!('withCredentials' in xhr) && global.XDomainRequest) {
						xhr = new XDomainRequest(); // CORS with IE8/9
						xdr = true;
						if(method!='GET' && method!='POST') {
							method = 'POST';
						}
					}
				}
				// Open connection
				if(xdr) {
					xhr.open(method, url);
				}
				else {
					xhr.open(method, url, options.async, options.user, options.password);
					if(xhr2 && options.async) {
						xhr.withCredentials = options.withCredentials;
					}
				}
				// Set headers
				if(!xdr) {
					for(var i in headers) {
						if(headers[i]) {
							xhr.setRequestHeader(i, headers[i]);
						}
					}
				}
				// Verify if the response type is supported by the current browser
				if(xhr2 && options.responseType!='document' && options.responseType!='auto') { // Don't verify for 'document' since we're using an internal routine
					try {
						xhr.responseType = options.responseType;
						nativeResponseParsing = (xhr.responseType==options.responseType);
					}
					catch(e){}
				}
				// Plug response handler
				if(xhr2 || xdr) {
					xhr.onload = handleResponse;
					xhr.onerror = handleError;
				}
				else {
					xhr.onreadystatechange = function() {
						if(xhr.readyState == 4) {
							handleResponse();
						}
					};
				}
				// Override mime type to ensure the response is well parsed
				if(options.responseType!='auto' && 'overrideMimeType' in xhr) {
					xhr.overrideMimeType(mimeTypes[options.responseType]);
				}
				// Run 'before' callback
				if(before) {
					before(xhr);
				}
				// Send request
				if(xdr) {
					setTimeout(function(){ // https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest
						xhr.send(method!='GET'?data:null);
					},0);
				}
				else {
					xhr.send(method!='GET'?data:null);
				}
			};
			return pinky;
		}),

		// Handle the response
		handleResponse = function() {
			// Prepare
			var i, responseType;
			--requests;
			sending = false;
			// Verify timeout state
			// --- https://stackoverflow.com/questions/7287706/ie-9-javascript-error-c00c023f
			if(new Date().getTime()-timeout_start >= options.timeout) {
				if(!options.attempts || ++attempts!=options.attempts) {
					promise.send();
				}
				else {
					promise(false, [xhr,response,new Error('Timeout ('+url+')')]);
				}
				return;
			}
			// Launch next stacked request
			if(request_stack.length) {
				request_stack.shift().send();
			}
			// Handle response
			try{
				// Process response
				if(nativeResponseParsing && 'response' in xhr && xhr.response!==null) {
					response = xhr.response;
				}
				else if(options.responseType == 'document') {
					var frame = document.createElement('iframe');
					frame.style.display = 'none';
					document.body.appendChild(frame);
					frame.contentDocument.open();
					frame.contentDocument.write(xhr.response);
					frame.contentDocument.close();
					response = frame.contentDocument;
					document.body.removeChild(frame);
				}
				else{
					// Guess response type
					responseType = options.responseType;
					if(responseType == 'auto') {
						if(xdr) {
							responseType = defaultXdrResponseType;
						}
						else {
							var ct = xhr.getResponseHeader('Content-Type') || '';
							if(ct.indexOf(mimeTypes.json)>-1) {
								responseType = 'json';
							}
							else if(ct.indexOf(mimeTypes.xml)>-1) {
								responseType = 'xml';
							}
							else {
								responseType = 'text';
							}
						}
					}
					// Handle response type
					switch(responseType) {
						case 'json':
							try {
								if('JSON' in global) {
									response = JSON.parse(xhr.responseText);
								}
								else {
									response = eval('('+xhr.responseText+')');
								}
							}
							catch(e) {
								throw "Error while parsing JSON body : "+e;
							}
							break;
						case 'xml':
							// Based on jQuery's parseXML() function
							try {
								// Standard
								if(global.DOMParser) {
									response = (new DOMParser()).parseFromString(xhr.responseText,'text/xml');
								}
								// IE<9
								else {
									response = new ActiveXObject('Microsoft.XMLDOM');
									response.async = 'false';
									response.loadXML(xhr.responseText);
								}
							}
							catch(e) {
								response = undefined;
							}
							if(!response || !response.documentElement || response.getElementsByTagName('parsererror').length) {
								throw 'Invalid XML';
							}
							break;
						default:
							response = xhr.responseText;
					}
				}
				// Late status code verification to allow passing data when, per example, a 409 is returned
				// --- https://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
				if('status' in xhr && !/^2|1223/.test(xhr.status)) {
					throw xhr.status+' ('+xhr.statusText+')';
				}
				// Fulfilled
				promise(true, [xhr,response]);
			}
			catch(e) {
				// Rejected
				promise(false, [xhr,response,e]);
			}
		},

		// Handle errors
		handleError = function(e) {
			--requests;
			promise(false, [xhr,null,new Error('Connection aborted')]);
		};

		// Normalize options
		options.async = 'async' in options?!!options.async:true;
		options.cache = 'cache' in options?!!options.cache:false;
		options.dataType = 'dataType' in options?options.dataType.toLowerCase():'post';
		options.responseType = 'responseType' in options?options.responseType.toLowerCase():'auto';
		options.user = options.user || '';
		options.password = options.password || '';
		options.withCredentials = !!options.withCredentials;
		options.timeout = 'timeout' in options?parseInt(options.timeout,10):30000;
		options.attempts = 'attempts' in options?parseInt(options.attempts,10):1;

		// Guess if we're dealing with a cross-origin request
		i = url.match(/\/\/(.+?)\//);
		crossOrigin = i && (i[1]?i[1]!=location.host:false);

		// Prepare data
		if('ArrayBuffer' in global && data instanceof ArrayBuffer) {
			options.dataType = 'arraybuffer';
		}
		else if('Blob' in global && data instanceof Blob) {
			options.dataType = 'blob';
		}
		else if('Document' in global && data instanceof Document) {
			options.dataType = 'document';
		}
		else if('FormData' in global && data instanceof FormData) {
			options.dataType = 'formdata';
		}
		switch(options.dataType) {
			case 'json':
				data = JSON.stringify(data);
				break;
			case 'post':
				data = jparam(data);
		}

		// Prepare headers
		if(options.headers) {
			var format = function(match,p1,p2) {
				return p1 + p2.toUpperCase();
			};
			for(i in options.headers) {
				headers[i.replace(/(^|-)([^-])/g,format)] = options.headers[i];
			}
		}
		if(!('Content-Type' in headers) && method!='GET') {
			if(options.dataType in mimeTypes) {
				if(mimeTypes[options.dataType]) {
					headers['Content-Type'] = mimeTypes[options.dataType];
				}
			}
		}
		if(!headers.Accept) {
			headers.Accept = (options.responseType in accept)?accept[options.responseType]:'*/*';
		}
		if(!crossOrigin && !('X-Requested-With' in headers)) { // (that header breaks in legacy browsers with CORS)
			headers['X-Requested-With'] = 'XMLHttpRequest';
		}
		if(!options.cache && !('Cache-Control' in headers)) {
			headers['Cache-Control'] = 'no-cache';
		}

		// Prepare URL
		if(method=='GET' && data) {
			vars += data;
		}
		if(vars) {
			url += (/\?/.test(url)?'&':'?')+vars;
		}

		// Start the request
		if(options.async) {
			promise.send();
		}

		// Return promise
		return promise;

	};

	// Return the external qwest object
	return {
		base: '',
		get: function(url, data, options, before) {
			return qwest('GET', this.base+url, data, options, before);
		},
		post: function(url, data, options, before) {
			return qwest('POST', this.base+url, data, options, before);
		},
		put: function(url, data, options, before) {
			return qwest('PUT', this.base+url, data, options, before);
		},
		'delete': function(url, data, options, before) {
			return qwest('DELETE', this.base+url, data, options, before);
		},
		map: function(type, url, data, options, before) {
			return qwest(type.toUpperCase(), this.base+url, data, options, before);
		},
		xhr2: xhr2,
		// obsolete
		limit: function(by) {
			limit = by;
		},
		// obsolete
		setDefaultXdrResponseType: function(type) {
			defaultXdrResponseType = type.toLowerCase();
		}
	};

}();

},{"jquery-param":2,"pinkyswear":3}]},{},[2,3])("qwest")
});

;(function(win){
	var store = {},
		doc = win.document,
		localStorageName = 'localStorage',
		scriptTag = 'script',
		storage

	store.disabled = false
	store.version = '1.3.17'
	store.set = function(key, value) {}
	store.get = function(key, defaultVal) {}
	store.has = function(key) { return store.get(key) !== undefined }
	store.remove = function(key) {}
	store.clear = function() {}
	store.transact = function(key, defaultVal, transactionFn) {
		if (transactionFn == null) {
			transactionFn = defaultVal
			defaultVal = null
		}
		if (defaultVal == null) {
			defaultVal = {}
		}
		var val = store.get(key, defaultVal)
		transactionFn(val)
		store.set(key, val)
	}
	store.getAll = function() {}
	store.forEach = function() {}

	store.serialize = function(value) {
		return JSON.stringify(value)
	}
	store.deserialize = function(value) {
		if (typeof value != 'string') { return undefined }
		try { return JSON.parse(value) }
		catch(e) { return value || undefined }
	}

	// Functions to encapsulate questionable FireFox 3.6.13 behavior
	// when about.config::dom.storage.enabled === false
	// See https://github.com/marcuswestin/store.js/issues#issue/13
	function isLocalStorageNameSupported() {
		try { return (localStorageName in win && win[localStorageName]) }
		catch(err) { return false }
	}

	if (isLocalStorageNameSupported()) {
		storage = win[localStorageName]
		store.set = function(key, val) {
			if (val === undefined) { return store.remove(key) }
			storage.setItem(key, store.serialize(val))
			return val
		}
		store.get = function(key, defaultVal) {
			var val = store.deserialize(storage.getItem(key))
			return (val === undefined ? defaultVal : val)
		}
		store.remove = function(key) { storage.removeItem(key) }
		store.clear = function() { storage.clear() }
		store.getAll = function() {
			var ret = {}
			store.forEach(function(key, val) {
				ret[key] = val
			})
			return ret
		}
		store.forEach = function(callback) {
			for (var i=0; i<storage.length; i++) {
				var key = storage.key(i)
				callback(key, store.get(key))
			}
		}
	} else if (doc.documentElement.addBehavior) {
		var storageOwner,
			storageContainer
		// Since #userData storage applies only to specific paths, we need to
		// somehow link our data to a specific path.  We choose /favicon.ico
		// as a pretty safe option, since all browsers already make a request to
		// this URL anyway and being a 404 will not hurt us here.  We wrap an
		// iframe pointing to the favicon in an ActiveXObject(htmlfile) object
		// (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
		// since the iframe access rules appear to allow direct access and
		// manipulation of the document element, even for a 404 page.  This
		// document can be used instead of the current document (which would
		// have been limited to the current path) to perform #userData storage.
		try {
			storageContainer = new ActiveXObject('htmlfile')
			storageContainer.open()
			storageContainer.write('<'+scriptTag+'>document.w=window</'+scriptTag+'><iframe src="/favicon.ico"></iframe>')
			storageContainer.close()
			storageOwner = storageContainer.w.frames[0].document
			storage = storageOwner.createElement('div')
		} catch(e) {
			// somehow ActiveXObject instantiation failed (perhaps some special
			// security settings or otherwse), fall back to per-path storage
			storage = doc.createElement('div')
			storageOwner = doc.body
		}
		var withIEStorage = function(storeFunction) {
			return function() {
				var args = Array.prototype.slice.call(arguments, 0)
				args.unshift(storage)
				// See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
				// and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
				storageOwner.appendChild(storage)
				storage.addBehavior('#default#userData')
				storage.load(localStorageName)
				var result = storeFunction.apply(store, args)
				storageOwner.removeChild(storage)
				return result
			}
		}

		// In IE7, keys cannot start with a digit or contain certain chars.
		// See https://github.com/marcuswestin/store.js/issues/40
		// See https://github.com/marcuswestin/store.js/issues/83
		var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g")
		function ieKeyFix(key) {
			return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___')
		}
		store.set = withIEStorage(function(storage, key, val) {
			key = ieKeyFix(key)
			if (val === undefined) { return store.remove(key) }
			storage.setAttribute(key, store.serialize(val))
			storage.save(localStorageName)
			return val
		})
		store.get = withIEStorage(function(storage, key, defaultVal) {
			key = ieKeyFix(key)
			var val = store.deserialize(storage.getAttribute(key))
			return (val === undefined ? defaultVal : val)
		})
		store.remove = withIEStorage(function(storage, key) {
			key = ieKeyFix(key)
			storage.removeAttribute(key)
			storage.save(localStorageName)
		})
		store.clear = withIEStorage(function(storage) {
			var attributes = storage.XMLDocument.documentElement.attributes
			storage.load(localStorageName)
			for (var i=0, attr; attr=attributes[i]; i++) {
				storage.removeAttribute(attr.name)
			}
			storage.save(localStorageName)
		})
		store.getAll = function(storage) {
			var ret = {}
			store.forEach(function(key, val) {
				ret[key] = val
			})
			return ret
		}
		store.forEach = withIEStorage(function(storage, callback) {
			var attributes = storage.XMLDocument.documentElement.attributes
			for (var i=0, attr; attr=attributes[i]; ++i) {
				callback(attr.name, store.deserialize(storage.getAttribute(attr.name)))
			}
		})
	}

	try {
		var testKey = '__storejs__'
		store.set(testKey, testKey)
		if (store.get(testKey) != testKey) { store.disabled = true }
		store.remove(testKey)
	} catch(e) {
		store.disabled = true
	}
	store.enabled = !store.disabled

	if (typeof module != 'undefined' && module.exports && this.module !== module) { module.exports = store }
	else if (typeof define === 'function' && define.amd) { define(store) }
	else { win.store = store }

})(Function('return this')());


/**
 * Touch Event
 *
 * provide tap sweepLeft sweepRight sweepTop sweepDown 
 */
;(function(win){
	var CustomEvent = function(type, config) {
		var e = document.createEvent('CustomEvent');
		e.initCustomEvent(type, config.bubbles, config.cancelable, config.detail);
		return e;
	};
	var NOW = function(){
		return +(new Date);
	};
	var getPageX = function(e){
		return e.pageX || e.touches[0].pageX;
	};
	var getPageY = function(e){
		return e.pageY || e.touches[0].pageY;
	}
	var target, startX, startY, pageX, pageY, offsetX, offsetY, startTime, onTouchStart, onTouchMove, onTouchEnd, onTouchCancel, config;
	config = {
		tapThreshold: {
			move: 5,
			time: 300
		},
		sweepThreshold: {
			move: 5
		}

	};
	onTouchStart = function(e) {
		startTime = NOW();
		startX = pageX = getPageX(e);
		startY = pageY = getPageY(e);
		target = e.target;
	};

	onTouchMove = function(e) {
		pageX = getPageX(e);
		pageY = getPageY(e);
	};

	onTouchCancel = onTouchEnd = function(e) {
		var timelapse, absOffsetX, absOffsetY, maxOffset, isTap, isSweep, isSweepLeft, isSweepRight, isSweepUp, isSweepDown, eventType;
		timelapse = NOW() - startTime;
		offsetX = pageX - startX;
		offsetY = pageY - startY;
		absOffsetX = Math.abs(offsetX);
		absOffsetY = Math.abs(offsetY);
		maxOffset = Math.max(absOffsetX, absOffsetY);
		//console.log(timelapse,offsetX, offsetY, maxOffset)
		if(timelapse <= config.tapThreshold.time && maxOffset <= config.tapThreshold.move){
			isTap = true;
			eventType = 'tap';
		}else{
			if(maxOffset > config.sweepThreshold.move){
				isSweep = true;
				if(absOffsetX > absOffsetY){
					if(offsetX > 0){
						isSweepRight = true;
						eventType = 'sweepright';
					}else{
						isSweepLeft = true;
						eventType = 'sweepleft';
					}
				}else{
					if(offsetY > 0){
						isSweepDown = true;
						eventType = 'sweepdown';
					}else{
						isSweepUp = true;
						eventType = 'sweepup';
					}
				}
				
			}
		}
	/*	
		var info = 'elapse time: ' + timelapse + '<br>offset x: ' + offsetX + '<br>offset y: ' + offsetY + '<br>max offset: ' + maxOffset + '<br>is tap: ' + isTap + '<br>is sweep: ' + isSweep + '<br>is sweep left: ' + isSweepLeft + '<br>is sweep right: ' + isSweepRight + '<br>is sweep up: ' + isSweepUp + '<br>is sweep down: ' + isSweepDown;
		console.log(info.replace(/\<br\>/g, '\n'));
	*/	
		if(eventType && target){
			var customEvent = new CustomEvent(eventType, {
				bubbles: true,
				cancelable: true
			});
			target.dispatchEvent(customEvent);
		}
	};

	var addEvent = function(element, type, fn){
		if(!element)
			return
		if(win.attachEvent){
			element.attachEvent("on" + type, fn);
		}else{
			element.addEventListener(type, fn, false);
		}
	};
	if('ontouchstart' in win) {
		window.addEventListener('touchstart', onTouchStart);
		window.addEventListener('touchmove', onTouchMove);
		window.addEventListener('touchend', onTouchEnd);
	}
	else {
		addEvent(win, 'click', function(e){
			var event = e || window.event;
			var ele = event.target;
			if(ele){
				var customEvent = new CustomEvent('tap', {bubbles: true, cancelable: true});
				ele.dispatchEvent(customEvent);
			}
		});
	}
	if('ontouchcancel' in win) {
		window.addEventListener('touchcancel', onTouchCancel);
	}
})(window);

;(function(win){
	win.Browser = {};
	var ua = navigator.userAgent.toLowerCase();
  var UA = ua.match(/(opera|ie|firefox|chrome|trident|crios|version)[\s\/:]([\w\d\.]+)?.*?(safari|(?:rv[\s\/:]|version[\s\/:])([\w\d\.]+)|$)/) || [null, 'unknown', 0];
  if (UA[1] == 'trident'){
      UA[1] = 'ie';
      if (UA[4]) UA[2] = UA[4];
  } else if (UA[1] == 'crios'){
      UA[1] = 'chrome';
  }
  var platform ;
  if(ua.match(/ip(?:ad|od|hone)/)){
    platform = 'ios';
  }else if(platform = ua.match(/(?:webos|android)/)){
    platform = platform[0];
  }else if(platform = ua.match(/mac|win|linux/)){
    platform = platform[0];
  }else{
    platform = 'other';
  }
  if (platform == 'win') platform = 'windows';

  var app = /micromessenger/.test(ua) ? 'wechat' : ( /qq/.test(ua) ? 'qq' : (/weibo/.test(ua) ? 'weibo' : (/com\.xisue\.zhoumo/.test(ua) ? 'xisue' : '')));

  Browser.name = (UA[1] == 'version') ? UA[3] : UA[1];
  Browser.version =  parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]);
  Browser.platform = platform;
  Browser.app = app;

  Browser.name = (UA[1] == 'version') ? UA[3] : UA[1];
	Browser.version =  parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]);
	Browser.platform = platform;
	Browser.app = app;
  try{
    if(app == 'xisue'){
      var appVersion = ua.match(/com\.xisue\.zhoumo(?:\.devel)?\/(\d)\.(\d)(?:\.(\d))?/);
      if(appVersion){
        Browser.appv_1 = appVersion[1] || null;
        Browser.appv_2 = appVersion[2] || null;
        Browser.appv_3 = appVersion[3] || null;
      }
    }
  }catch(err){
    console.log('xisue ua 正则式需调整');
  }
	var styles = window.getComputedStyle(document.documentElement, '');
	var stylesStr = '';
	try{
		stylesStr = Array.prototype.slice.call(styles).join('');
	}catch(error){
		// 锤子手机浏览 iligal access
		for(var i = 0,l = styles.length; i < l; i++){
			stylesStr += styles[i];
		}
	}
	
  var pre = (stylesStr.match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']))[1];
  Browser.cssPrefix = '-' + pre + '-';
  Browser.transform = pre[0].toUpperCase() + pre.substr(1) + 'Transform';
  var el = document.createElement('div');
  var transEndEventNames = {
    WebkitTransition : 'webkitTransitionEnd',
    MozTransition : 'transitionend',
    OTransition : 'oTransitionEnd otransitionend',
    transition : 'transitionend'
  };
  for (var name in transEndEventNames) {
    if (el.style[name] !== undefined) {
      Browser.transEndName = transEndEventNames[name];
      break;
    }
  }
                
})(window)
;(function(global){
	var codeMap = ['a','b','c','d','e','f','g','h','i','j'];

	var utils = global.utils = {
		n2s: function(num){
			num = num + '';
			num = num.split('');
			var newArr = [];
			num.forEach(function(v,k){
				newArr.push(codeMap[v]);
			});
			return newArr.join('');
		},
		s2n: function(str){
			str = str + '';
			str = str.split('');
			var newArr = [];
			str.forEach(function(v,k){
				newArr.push(codeMap.indexOf(v));
			});
			return newArr.join('');
		},
		round2: function(num, precision){
			num = num || 0;
			precision = precision || 2;
			var dnum = Math.pow(10, precision);
			if(
				Math.floor(num*dnum*10)%5 == 0 && 
				Math.floor(num*dnum*10) == num*dnum*10 && 
				Math.floor(num*dnum)%2 == 0
				){
				return Math.floor(num*dnum)/dnum;
			}else{
				return Math.round(num*dnum)/dnum;
			}

		},
		obj2qs: function(obj){
			obj = obj || {};
			var qs = '?';
			$.each(obj, function(key, value){
				if(key && value){
					qs += key + '=' + value + '&';	
				}
			});
			return qs.length > 1 ? qs : '';
		},
		linkConvert: function(link, city, name){
		var r = '', qs;
		qs = parseQuery(link);	
		if(/^http/.test(link)){
			r = link;
		}else if(/^inapp:\/\/actlist/.test(link)){
			if(!city){
				r = '/category' + object2query(qs);
			}else{
				r = '/' + city;	
				if(/\d+/.test(qs.genre_id)){
					r += '/category/' + qs.genre_id;
					delete qs.genre_id;
				}else{
					r += '/hot';	
				}
				r += object2query(qs);
			}	
		}else if(/^inapp:\/\/main/.test(link)){
      r = '/search';
		}else if(/^inapp:\/\/act/.test(link) && /\d+/.test(qs.id)){
			r = '/huodong/' + qs.id;	
		}else if(/^inapp:\/\/topic/.test(link) && /\d+/.test(qs.id)){
			r = '/zhuanti/' + qs.id;	
		}else if(/^inapp:\/\/marketing/.test(link) && /\d+/.test(qs.id)){
			r = '/marketing/' + qs.id;	
		}else if(/^inapp:\/\/(user|order|shop|login|topiclist|calendar|dailylist|nearby)/.test(link)){
			r = link;
		}else{
			r = link.replace(/^inapp/, 'http');	
			if(!/^http/.test(r)){
				r = 'http://' + r;	
			}
		}
		if(typeof sticky !== 'undefined' && sticky != ''){
			if(r.indexOf('?') > -1){
				r += '&' + sticky;
			}else{
				r += '?' + sticky;
			}
		}
		return r;
	},
	parseQuery: function(queryString){
		var params = {}, idx;
		queryString = queryString || location.search || '',
		idx = queryString.indexOf('?');
		if(idx > -1){
			queryString = queryString.slice(idx + 1);	
		}else{
			queryString = '';	
		}
		if(queryString){
			queryString = queryString.split('&');
			var i, l, q, key, value;
			for(i = 0, l = queryString.length; i < l; i++){
				q = queryString[i];
				q = q.split('=');
				key = q[0];
				value = q[1];
				params[key] = value;
			}
		}
		return params;
	},
	stickyParams: ['paysource','zmsource','cmbsource','hdl', 'cooper'],
	blockedParams: ['UUID','top_session'],
	getSticky: function(params){
		var sticky = '';
		var keys,k,v;
		keys = Object.keys(params);
		keys.forEach(function(k){
			if(utils.stickyParams.indexOf(k) > -1){
				sticky += '&' + k + '=' + params[k];	
			}	
		});
		return sticky.replace(/^&/,'');
	},
		isPassport: function(str){
			var RE = /[0-9a-zA-Z]{4,32}/;
			if(RE.test(str)) return true;
			return false;
		},
		/**
     * Mobile validation function
     *
     * number in china
     */
    isMobile: function(str){
        //var mobileRE = /^13\d{9}|14[57]\d{8}|15[012356789]\d{8}|18[01256789]\d{8}|170\d{8}$/;
        var mobileRE = /^1[34587]\d{9}$/;
        if(mobileRE.test(str))
            return true;
        return false;
    },

    /**
     * check all number
     *
     */
    isNumber: function(str, num){
        var RE;
        if(!num){
            RE = /^\d+$/;
        }else {
            RE = new RegExp('^\\d\{' + num + '\}$');
        }
        if(RE.test(str))
            return true;
        return false;
    },
    isEmail: function(emailAdress){
        //var emailRE = /^[a-zA-Z0-9-_\.]+@[a-zA-Z0-9-_\.]+$/;
        //var emailRE = /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/;
        var emailRE = /^(?:[-\w])+(?:\.[-\w]+)*@(?:[-\w])+(?:(?:\.[-\w]+)+)$/;
        if(emailAdress && emailRE.test(emailAdress)){
            return true;
        }
        return false;
    },
    showMsg: function(msg, delay){
        var ele = $('<div>');
        if(Browser.platform == 'ios'){
            var top = $(window).scrollTop() + 100;
            ele.attr('class', 'zw-tossMsg-top')
                .css('top', top)
                .text(msg);
        }else{
            ele.attr('class', 'zw-tossMsg')
                .text(msg);
        }
        $('body').append(ele);
        if(delay){
            return setTimeout(function(){
                ele.remove();
            }, delay);
        }
        return ele;
    },
		showMsgDelay: function(msg, delay){
        setTimeout(function(){
            utils.showMsg(msg, delay);
        }, 100);
    },
    getBeginDate: function(){
    	var now = new Date();
    	var year = now.getFullYear();
    	var month = utils.zeroPadding(now.getMonth() + 1, 2);
    	var date = utils.zeroPadding(now.getDate(), 2);
    	return year + '-' + month + '-' + date;
    },
    getEndDate: function(delayMonth){
    	var delayMonth = delayMonth || 3;
    	var now = new Date();
    	var year, month, date;
    	month = now.getMonth();
    	now.setMonth(month + delayMonth);
    	year = now.getFullYear();
    	month = utils.zeroPadding(now.getMonth() + 1, 2);
    	date = utils.zeroPadding(now.getDate(), 2);
    	return year + '-' + month + '-' + date;
    },
    parseDate: function(dates){
        var data = dates;
        var re = /(\d+)-(\d+)-(\d+)/;
        var days = {}, day, key, value, i, l;

        for(i = 0, l = data.length; i < l; i++){
            day = data[i].match(re);
            if(day){
                key = day[1] + day[2];
                value = parseInt(day[3]) + '';
                if(days[key] === undefined){
                    days[key] = [];
                }
                days[key].push(value);
            }
        }
        return days;
    },
    getLocalDateString: function(dateStr){
        var r, t, re, fullYear, month, dateArr, date,  days, day;
        days = ["周日","周一","周二","周三","周四","周五","周六"];
        t = new Date();
        re = /(\d+)-(\d+)-(\d+)/;
        dateArr = dateStr.match(re);
        fullYear = dateArr[1];
        month = dateArr[2] - 0;
        date = dateArr[3] - 0;
        r = '' + fullYear + "年";
        r += month + "月";
        r += date + "日";
        // 避免在设置月日期时出现意外变动，将日期设置为1月1号
        t.setDate(1);
        t.setMonth(0);

        t.setFullYear(fullYear);
        t.setMonth(month - 1);
        t.setDate(date);

        day = t.getDay();
        r += ' ' + days[day];

        return r;
    },
    zeroPadding: function(n, pad){
        var i,l, r = '';
        n = n + '';
        if(n.length < pad){
            l = pad - n.length;
            for(i = 0; i < l; i++){
                r += '0' + n;
            }
        }else{
            r = n;
        }
        return r;
    },
    makeArray: function(str){
        var r = [];
        for(var i = 0, l = str.length; i < l; i++ ){
            r.push(str[i]);
        }
        return r;
    },
    isIdCard: function(num){
    	var idCardRE = /(^\d{15}$)|(^\d{17}([0-9]|[Xx])$)/;
    	if(idCardRE.test(num))
    		return true
    	return false
    },
		json: {
			encode: function(obj){
				var r;
				if(typeof obj !== 'string'){
					try {
						r = JSON.stringify(obj);	
					}catch(err){
						
					}	
				}
				return r ? r : obj;
			},
			decode: function(str){
				var r;
				if(typeof str === 'string'){
					try {
						r = JSON.parse(str);	
					}catch(err){
						
					}	
				}
				return r ? r : str;
			}
		},
		timestamp: function(){
			return Math.round((new Date) / 1000);	
		},
		jstimestamp: function(){
			return +new Date;	
		},
		getuid: function (length) {
			if(typeof length === 'undefined') {
				length = 10;
			}
	
			var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
			var name = '';
			var i = 0;
	
			while(i < length) {
				name += chars[Math.floor((Math.random() * (chars.length-1))+1)];
				i++;
			}
	
			return name;
		},
		getRandomNumber: function(num){
			if(!num || num > 16)
				num = 6;
			var re = new RegExp('0\\\.0*(\\\d{' + num + '})');
			return (Math.random() + "").match(re)[1];
		},
		range: function(num, step){ 
			var r = [];
			var step = step || 1;
			for(var i = 0; i < num; i++){ 
				r[i] = typeof r[i - 1] === 'undefined' ? 0 : r[i - 1] + step; 
			}
			return r;
		},
		random: function(min, max){ 
			if(typeof max === 'undefined'){ 
				max = min;
				min = 0;
			}
			return Math.floor(min + (max - min)*Math.random());
		}
	
	}
	if(typeof Array.prototype.shuffle !== 'function'){
		Array.prototype.shuffle = function(){ 
			var srcArr = this,
				targetArr = [],
				i, length, item, randex, targetLastIndex, switchItem;
			for(i = 0, length = srcArr.length; i < length; i++){ 
				item = srcArr[i];
				targetLastIndex = targetArr.length;
				randex = utils.random(targetLastIndex);
				switchItem = targetArr[randex];
				targetArr[randex] = item;
				typeof switchItem !== 'undefined' && (targetArr[targetLastIndex] = switchItem);
			}
			return targetArr;
		}
	}
})(typeof window !== 'undefined' ? window : this)

;(function(global){
	global.CON = {
		localkey: 'zwlocaldata',
		localgeo: 'zwgeolocation',
		localhc: 'zwhotcity',
		localcl: 'zwpoilist',
		update: 'update',
		actcity: 'zwactivecity',
		usidkey: 'zwusid'
			
	};
})(typeof window !== 'undefined' ? window : this);
/*
 * Cookies.js - 1.2.2
 * https://github.com/ScottHamper/Cookies
 *
 * This is free and unencumbered software released into the public domain.
 */
;(function (global, undefined) {
    'use strict';

    var factory = function (window) {
        if (typeof window.document !== 'object') {
            throw new Error('Cookies.js requires a `window` with a `document` object');
        }

        var Cookies = function (key, value, options) {
            return arguments.length === 1 ?
                Cookies.get(key) : Cookies.set(key, value, options);
        };

        // Allows for setter injection in unit tests
        Cookies._document = window.document;

        // Used to ensure cookie keys do not collide with
        // built-in `Object` properties
        Cookies._cacheKeyPrefix = 'cookey.'; // Hurr hurr, :)
        
        Cookies._maxExpireDate = new Date('Fri, 31 Dec 9999 23:59:59 UTC');

        Cookies.defaults = {
            path: '/',
            secure: false
        };

        Cookies.get = function (key) {
            if (Cookies._cachedDocumentCookie !== Cookies._document.cookie) {
                Cookies._renewCache();
            }
            
            var value = Cookies._cache[Cookies._cacheKeyPrefix + key];

            return value === undefined ? undefined : decodeURIComponent(value);
        };

        Cookies.set = function (key, value, options) {
            options = Cookies._getExtendedOptions(options);
            options.expires = Cookies._getExpiresDate(value === undefined ? -1 : options.expires);

            Cookies._document.cookie = Cookies._generateCookieString(key, value, options);

            return Cookies;
        };

        Cookies.expire = function (key, options) {
            return Cookies.set(key, undefined, options);
        };

        Cookies._getExtendedOptions = function (options) {
            return {
                path: options && options.path || Cookies.defaults.path,
                domain: options && options.domain || Cookies.defaults.domain,
                expires: options && options.expires || Cookies.defaults.expires,
                secure: options && options.secure !== undefined ?  options.secure : Cookies.defaults.secure
            };
        };

        Cookies._isValidDate = function (date) {
            return Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime());
        };

        Cookies._getExpiresDate = function (expires, now) {
            now = now || new Date();

            if (typeof expires === 'number') {
                expires = expires === Infinity ?
                    Cookies._maxExpireDate : new Date(now.getTime() + expires * 1000);
            } else if (typeof expires === 'string') {
                expires = new Date(expires);
            }

            if (expires && !Cookies._isValidDate(expires)) {
                throw new Error('`expires` parameter cannot be converted to a valid Date instance');
            }

            return expires;
        };

        Cookies._generateCookieString = function (key, value, options) {
            key = key.replace(/[^#$&+\^`|]/g, encodeURIComponent);
            key = key.replace(/\(/g, '%28').replace(/\)/g, '%29');
            value = (value + '').replace(/[^!#$&-+\--:<-\[\]-~]/g, encodeURIComponent);
            options = options || {};

            var cookieString = key + '=' + value;
            cookieString += options.path ? ';path=' + options.path : '';
            cookieString += options.domain ? ';domain=' + options.domain : '';
            cookieString += options.expires ? ';expires=' + options.expires.toUTCString() : '';
            cookieString += options.secure ? ';secure' : '';

            return cookieString;
        };

        Cookies._getCacheFromString = function (documentCookie) {
            var cookieCache = {};
            var cookiesArray = documentCookie ? documentCookie.split('; ') : [];

            for (var i = 0; i < cookiesArray.length; i++) {
                var cookieKvp = Cookies._getKeyValuePairFromCookieString(cookiesArray[i]);

                if (cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] === undefined) {
                    cookieCache[Cookies._cacheKeyPrefix + cookieKvp.key] = cookieKvp.value;
                }
            }

            return cookieCache;
        };

        Cookies._getKeyValuePairFromCookieString = function (cookieString) {
            // "=" is a valid character in a cookie value according to RFC6265, so cannot `split('=')`
            var separatorIndex = cookieString.indexOf('=');

            // IE omits the "=" when the cookie value is an empty string
            separatorIndex = separatorIndex < 0 ? cookieString.length : separatorIndex;

            var key = cookieString.substr(0, separatorIndex);
            var decodedKey;
            try {
                decodedKey = decodeURIComponent(key);
            } catch (e) {
                if (console && typeof console.error === 'function') {
                    console.error('Could not decode cookie with key "' + key + '"', e);
                }
            }
            
            return {
                key: decodedKey,
                value: cookieString.substr(separatorIndex + 1) // Defer decoding value until accessed
            };
        };

        Cookies._renewCache = function () {
            Cookies._cache = Cookies._getCacheFromString(Cookies._document.cookie);
            Cookies._cachedDocumentCookie = Cookies._document.cookie;
        };

        Cookies._areEnabled = function () {
            var testKey = 'cookies.js';
            var areEnabled = Cookies.set(testKey, 1).get(testKey) === '1';
            Cookies.expire(testKey);
            return areEnabled;
        };

        Cookies.enabled = Cookies._areEnabled();

        return Cookies;
    };

    var cookiesExport = typeof global.document === 'object' ? factory(global) : factory;

    // AMD support
    if (typeof define === 'function' && define.amd) {
        define(function () { return cookiesExport; });
    // CommonJS/Node.js support
    } else if (typeof exports === 'object') {
        // Support Node.js specific `module.exports` (which can be a function)
        if (typeof module === 'object' && typeof module.exports === 'object') {
            exports = module.exports = cookiesExport;
        }
        // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function)
        exports.Cookies = cookiesExport;
    } else {
        global.Cookies = cookiesExport;
    }
})(typeof window === 'undefined' ? this : window);
;(function(global){
	var getGeolocation = global.getGeolocation = function (cb) {
		var timeout,timeHandle;
		if(navigator.geolocation){
			navigator.geolocation.getCurrentPosition(function(position){
				var pos = {
					lat: position.coords.latitude,
					lon: position.coords.longitude
				};
				if(!timeout){
					cb(null, pos);
					if(timeHandle){
						clearTimeout(timeHandle);
						timeHandle = null;
					}
				}
			}, function(error){
				var errors = {
						1: 'Authorization fails', // permission denied
						2: 'Can\'t detect your location', //position unavailable
						3: 'Connection timeout' // timeout
				};
				if(!timeout){
					cb({code: error.code, message: errors[error.code]});
					if(timeHandle){
						clearTimeout(timeHandle);
						timeHandle = null;
					}
				}
			}, {
				enableHighAccuray: false	
			});	
			timeHandle = setTimeout(function(){
				cb({code: 4, message: 'timeout'});
				timeout = true;
				timeHandle = null;
			}, 5000);
		}else{
			cb({code:0,message:'no support'});	
		}	
	};
	
	var getCity = global.getCity = function(lon, lat, fn){
		qwest.get('/proxy', {
				api_path: '/other/lonlataddress',
				fields_version: '3.3',
				v: '3.0',
				lon: lon,
				lat: lat
			}, function(){
				
			})
			.then(function(xhr, response){
				var res = utils.json.decode(response);
				if(res && res.status == 'success'){
					var result = res.result;
					result.lon = lon;
					result.lat = lat;
					fn(null, result);
				}else{
					fn(utils.json.encode(response));		
				}
			})
			.catch(function(xhr, res, err ){
				fn(utils.json.encode(err));	
			})
			.complete(function(xhr,res){
				//console.log('request city complete');	
			});
	};
	var updatePosition = global.updatePosition = function(fn){
		getCity('', '', fn);
		/*
		getGeolocation(function(err, position){
			if(err){
				//utils.showMsg(err.code + ' ' + err.message, 5000);
				getCity('', '', fn);
			}else{
				getCity(position.lon, position.lat, fn);
			}	
		});
		*/
	};
	var correctPosition = global.correctPosition = function(){
		//utils.showMsg('update pos', 5000)
		updatePosition(function(err, result){
			if(err){
				//utils.showMsg(utils.json.encode(err), 5000);	
			}else{
				//utils.showMsg(utils.json.encode(result), 5000);
				if(!!result.lat && !!result.lon){
					Cookies.set('lon', result.lon)
						.set('lat', result.lat);
				}
				Cookies.set('city_id', result.city_id)
					.set('city', result.city)
					.set('city_pinyin', result.pinyin);
			}	
		});	
	};
})(typeof window !== 'undefined' ? window : this);
/**
 *  zw-slider
 *  
 */
;(function($, win, b){
	var getSrc = function(ele){
		if(ele.tagName.toLowerCase() == 'img')
			return ele.src;
		var backgroundImage = $(ele).css('backgroundImage');
		var match = backgroundImage.match(/url\((.*)\)/);
		return match ? match[1] : '';
	};
	$.fn.zwSlide = function(selector, currentEle){
		var selector = selector || '.zw-gp';
		
			var par = $(this);
			var isScrolling, slider, slideWidth, slideNumber, sliderString, containerWidth, containerHeight, marginRight = 15, slidesLength;
			var pageX,pageY,deltaX,deltaY,offsetX,lastSlide,startTime,resistance;

			var transformPrefix = b.cssPrefix;
			var transformProperty = b.transform;
			var getScroll = function(){
				var translate3d = slider[0].style[transformProperty].match(/translate3d\(([^,]*)/);
				var ret = translate3d ? translate3d[1] : 0;
				//console.log(ret);
				return parseInt(ret, 10);
			};

			var setSlideNumber = function (offset) {
		    var round = offset ? (deltaX < 0 ? 'ceil' : 'floor') : 'round';
		    slideNumber = Math[round](getScroll() / (slidesLength / slider.children().length));
		    slideNumber += offset;
		    slideNumber = Math.min(slideNumber, 0);
		    slideNumber = Math.max(-(slider.children().length - 1), slideNumber);
		  };

			var ontouchstart = function (e) {
				e.preventDefault();
		    e.stopPropagation();
		    isScrolling    = undefined;
		    resistance     = 1;
		    lastSlide      = -(slider.children().length - 1);
		    startTime      = +new Date();
		    pageX          = e.touches[0].pageX;
		    pageY          = e.touches[0].pageY;
		    deltaX         = 0;
		    deltaY         = 0;

		    setSlideNumber(0);

		    slider[0].style[transformPrefix + 'transition-duration'] = 0;
		  };
			var ontouchmove = function (e) {
		    if (e.touches.length > 1) {
		      return; // Exit if a pinch || no slider
		    }

		    
		    deltaX = e.touches[0].pageX - pageX;
		    deltaY = e.touches[0].pageY - pageY;
		    pageX  = e.touches[0].pageX;
		    pageY  = e.touches[0].pageY;

		    isScrolling = true;

		    offsetX = (deltaX / resistance) + getScroll();

		    e.preventDefault();

		    resistance = slideNumber === 0         && deltaX > 0 ? (pageX / slideWidth) + 1.25 :
		                 slideNumber === lastSlide && deltaX < 0 ? (Math.abs(pageX) / slideWidth) + 1.25 : 1;

		    slider[0].style[transformProperty] = 'translate3d(' + offsetX + 'px,0,0)';

		    
		  };
			var ontouchend = function (e) {
				if(!isScrolling){
					slider.parent().remove();
					return
				}
		    setSlideNumber((+new Date()) - startTime < 1000 && Math.abs(deltaX) > 15 ? (deltaX < 0 ? -1 : 1) : 0);

		    offsetX = slideNumber * slideWidth;

		    slider[0].style[transformPrefix + 'transition-duration'] = '.2s';
		    slider[0].style[transformProperty] = 'translate3d(' + offsetX + 'px,0,0)';

		  };

					currentEle = $(currentEle);
					var items = par.find(selector);
					var index = items.index(currentEle);

					containerWidth = $('body').width();
					containerHeight = screen.availHeight;
					slideWidth = containerWidth + marginRight;
					slidesLength = slideWidth * items.length;

					sliderString = '<div class="zw-slider-view" style="width:' + containerWidth + 'px;height:100%;position:fixed;left:50%;top:0;background:#000000;overflow:hidden;margin-left:-' + containerWidth / 2 + 'px"><div class="zw-slider-group" style="position:absolute;left:0;top:0;width:' + slidesLength + 'px;height:'+ containerHeight + 'px;">';
					items.each(function(){
						var item = $(this);
						sliderString += '<div style=\'width:' + containerWidth + 'px;margin-right:' + marginRight + 'px;height:'+ containerHeight + 'px;float:left;background-repeat:no-repeat;background-position:center;background-size:contain;background-image:url(' + getSrc(this) + ');\' ></div>';
					});
					sliderString += '</div></div>';
					var sliderView = $(sliderString);
					slider = sliderView.children();
					var curPos = -(index * slideWidth);
					slider[0].style[transformProperty] = 'translate3d(' + curPos + 'px,0,0)';
					$('body').append(sliderView);

					sliderView[0].addEventListener('touchmove', ontouchmove);
					sliderView[0].addEventListener('touchstart', ontouchstart);
					sliderView[0].addEventListener('touchend', ontouchend);
					sliderView[0].addEventListener('touchcancel', ontouchend);
					if(!window.ontouchstart){
						sliderView.on('tap', function(){
							slider.parent().remove();	
						});	
					}
	}
})(jQuery, window, Browser);
/**
 * zwlazyload
 *
 */
;(function($, win){
	
	$.fn.zwLazyload = function(selector, nobind){
		selector = selector ? selector : '[data-src]';
		this.each(function(){
			var container = $(this);
			var loads;
			var onscroll = function(){
				if(container.is(':hidden')){
					return	
				}
				loads = container.find(selector);
				if(loads.length > 0){
					var viewHeight = $(win).height();
					var scrollTop = $(win).scrollTop();
					loads.each(function(idx, ele){
						ele = $(ele);
						var offsetTop = ele.offset()['top'];
						var offsetBottom = offsetTop + ele.height();
						if( (offsetTop - scrollTop > 0 && offsetTop - scrollTop < viewHeight) ||
							(offsetBottom - scrollTop > 0 && offsetBottom - scrollTop < viewHeight)
							){
							var url = ele.attr('data-src');
							if(this.tagName.toLowerCase() == 'img'){
								ele.attr('src', url);
							}else{
								ele.css('backgroundImage', 'url(' + url + ')');	
							}
							ele.removeAttr('data-src');
						}
					});
				}
			};
			if(!nobind)
				$(win).bind('scroll', onscroll);
			// run lazyload at first
			onscroll();
		});
	}
	
})(jQuery, window);
;(function(global){
	var constents = {
        chromeIntent: "intent://#Intent;scheme=xishzmq;package=com.xisue.zhoumo;end",
        ios: "wb3903716518://zmqne",
        webIos: "itms-apps://itunes.apple.com/app/id820846113",
        webAndroid: "http://wanzhoumo.com/download?type=2&apk=A2",
        android: "xishzmq://",
        wechat: "http://a.app.qq.com/o/simple.jsp?pkgname=com.xisue.zhoumo",
        web: "http://wanzhoumo.com/",
        h5Activity: location.protocol + "//" + location.host + "/shanghai/huodong/",
        h5search: location.protocol + "//" + location.host + "/m/search/index?type=a&china=1&pinyin=lasa&keyword="
    };

    var loadIframe = null;
    function createIframe() {
        var iframe = document.createElement("iframe");
        iframe.style.cssText = "display:none;width:0px;height:0px;";
        document.body.appendChild(iframe);
        loadIframe = iframe;
    }


    var openApp = function(options) {
        var opts = options || {};
        var ua = navigator.userAgent;

        isIPhone = ua.match(/iPhone|iPod/i) != null;
        isIPad = ua.match(/iPad/i) != null;
        isAndroid = ua.match(/Android/i) != null;
        isChrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/);
        wechat = ua.toLowerCase().match(/micromessenger/);
        qq = ua.toLowerCase().match(/qq/);
        weibo = ua.toLowerCase().match(/weibo/);
        xisue = ua.toLowerCase().match(/com\.xisue\.zhoumo/);
        if(wechat || qq){
            if(opts.type == 'activity'){
                location.href = constents.h5Activity + opts.match;
            }else if(opts.type == 'tag'){
                location.href = constents.h5search + opts.match;
            }
            else{
                location.href = constents.wechat;
            }
        }
        else if (isIPhone || isIPad) {
            if(opts.type == 'activity' || opts.type == 'canjia'){
                loadIframe.src=constents.android + "act?id=" + opts.match;
            }else if(opts.type == 'tag'){
                loadIframe.src=constents.android + "actlist/?sort=distance&tag=" + opts.match;
            }
            else{
                loadIframe.src=constents.ios;
            }
            var loadTime = Date.now();
            setTimeout(function() {
                if (Date.now() - loadTime < 400) {
                    if(opts.type == 'activity'){
                        location.href = constents.h5Activity + opts.match;
                    }else if(opts.type == 'tag'){
                        location.href = constents.h5search + opts.match;
                    }
                    else{
                        location.href = constents.webIos;
                    }
                }
            }, 300);
        }
        else if (isAndroid) {
            if (isChrome) {
                if (opts.type == 'activity' || opts.type == 'canjia') {
                    location.href = "intent://act?id=" + opts.match + "#Intent;scheme=xishzmq;package=com.xisue.zhoumo;end";
                }else if (opts.type == 'tag'){
                    location.href = "intent://actlist/?sort=distance&tag=" + opts.match + "#Intent;scheme=xishzmq;package=com.xisue.zhoumo;end";
                }
                else {
                    location.href = "intent://#Intent;scheme=xishzmq;package=com.xisue.zhoumo;end";
                }
            } else {
                if(opts.type == 'activity' || opts.type == 'canjia'){
                    loadIframe.src = constents.android + "act?id=" + opts.match;
                }else if(opts.type == 'tag'){
                    loadIframe.src=constents.android + "actlist/?sort=distance&tag=" + opts.match;
                }
                else{
                    loadIframe.src = constents.android;
                }
            }
            var loadTime = Date.now();
            setTimeout(function() {
                if (Date.now() - loadTime < 400) {
                    if(opts.type == 'activity'){
                        location.href = constents.h5Activity + opts.match;
                    }else if(opts.type == 'tag'){
                        location.href = constents.h5search + opts.match;
                    }
                    else{
                        location.href = constents.webAndroid;
                    }
                }
            }, 300);
        }
        else {
            if(opts.type == 'activity'){
                location.href = constents.h5Activity + opts.match;
            }else if(opts.type == 'tag'){
                location.href = constents.h5search + opts.match;
            }
            else{
                location.href = constents.web;
            }
        }
    }
    var open = function(o){
        createIframe();
        openApp(o);
    }
    global.openApp = open;
})(typeof window !== 'undefined' ? window : this);

;(function(global){
	global.trackEvent = function(arr) {
		if(typeof _hmt !== 'undefined'){
			try{
				_hmt.push(arr);	
			}catch(err){
				console.log(err);	
			}	
		}	
	};	
})(typeof window !== 'undefined' ? window : this);
;(function(global, utils){
	global.zwBack = function(delay){
		
		delay = delay || 50;
		setTimeout(function(){
			var params = utils.parseQuery(), url = '/?', keys;
			if(history.length == 1){
				keys = Object.keys(params);
				keys.forEach(function(key){
					if(utils.stickyParams.indexOf(key) > -1)
						url += key + '=' + params[key] + '&';
				});
				location.href = url;
			}else{
				history.back();
			}
		}, delay);
	}
	
})(typeof window !== 'undefined' ? window : this, utils);
;(function(global){
		global.zwCalender = {
			getMonthDays: getMonthDays,
			getOffset: getOffset,
			getMonthDayCount: getMonthDayCount,
			isLeapYear: isLeapYear
		};
		function getMonthDays(yearmonth){
			yearmonth += '';
			var year = yearmonth.substr(0,4);
			var month = yearmonth.substr(4);
			var lastday = getMonthDayCount(year, month);
			var offset = getOffset(year, month);
			var days = [],r = {};
			var i, l, day;
			for(i = 0; i < offset; i++){
				days.push('0');
			}
			for(i = 0; i < lastday; i++){
				day = i + 1;
				days.push('' + day);
			}
			var supliment = days.length % 7 === 0 ? 0 : 7 - days.length % 7;

			for(i = 0; i < supliment; i++){
				days.push('0');
			}
			r[yearmonth] = days;
			return r;
		}
		function getOffset(year, month){
			var offset, t;
			t = new Date();
			t.setDate(1);
			t.setMonth(month - 1);
			t.setFullYear(year);
			offset = t.getDay();
			return offset;
		}
		function isNumber(arg){
			return /^\d+$/.test(arg);
		}
		function isLeapYear(year){
			return year % 100 === 0 ? ( year % 400 === 0 ? true : false ) : year % 4 === 0 ? true : false;
		}
		function getMonthDayCount(year,month){
			var count;
			switch(month){
				case 2:
				case '2':
					count = isLeapYear(year) ? 29 : 28;
					break;
				default:
					count = month < 8 ? ( month % 2 === 0 ? 30 : 31 ) : month % 2 === 0 ? 31 : 30;
			}
			return count;
		}
	})(typeof window !== 'undefined' ? window : this);
